from manimlib import*


class warning(Scene):
    def construct(self):
        back=Rectangle(
            FRAME_WIDTH,FRAME_HEIGHT,fill_color=RED,stroke_width=0
        )
        text=VGroup(Text("⚠",font="Segoe UI Emoji").set_color(YELLOW),Text("有强烈闪烁画面，光敏性癫痫者慎入",font="DengXian"),Text("⚠",font="Segoe UI Emoji").set_color(YELLOW),).arrange()
        back.add_updater(lambda m:m.set_fill(opacity=np.cos(self.time*PI)/2+1/2))
    
        self.add(back,text)
        self.wait(5)
        back.clear_updaters()
        self.play(FadeOut(text))
class waves(Scene):
    CONFIG={
        "func":lambda u,d,l,r:u+d+l+r,
        "func_label":r"U+D+L+R",
        "last":8,
        "textype":Tex,
        "iteration_speed":1,
        "fps60":1,
        "provider":None
    }
    def construct(self):
        side=51
        array=[[0 for i in range(side)] for i in range(side)]
        array[25][25]=1
        tex=self.textype(self.func_label).set_width(3).next_to(np.array([-FRAME_X_RADIUS/2-FRAME_Y_RADIUS/2,4,0]),DOWN)
        count=Integer().to_corner(DL)
        if self.provider != None:
            name=Text(self.provider,font="DengXian").set_width(2).next_to(tex,DOWN)

        if self.iteration_speed>1 or self.fps60!=1:
            speed=Tex("\\times",str(self.iteration_speed/self.fps60)).next_to(name,DOWN)

        def map_to(t):
            if t<=0:
                return 0
            elif t>=1:
                return 1
            else:
                return t
        a=0.4

        def change(grid):
            width=len(grid[0])
            height=len(grid)
            l=[]
            for i in range(height):
                for j in range(width):
                    l.append([(i,j),map_to(self.func(grid[(i-1)%height][j],grid[(i+1)%height][j],grid[i][(j-1)%width],grid[i][(j+1)%width],))])
            
            for index_and_num in l:
                i,j=index_and_num[0]
                array[i][j]=index_and_num[1]
        
        squ=Square(fill_color=WHITE,stroke_width=0).get_grid(side,side,height=8,buff=0).set_opacity(0)
        squ[25*51+25].set_opacity(1)

        self.add(squ)
        Animation=AnimationGroup(FadeIn(tex))
        Animation2=AnimationGroup(FadeOut(tex))
        if self.provider != None :
            Animation=AnimationGroup(FadeIn(tex),FadeIn(name))
            if self.iteration_speed>1 or self.fps60!=1:
                Animation2=AnimationGroup(FadeOut(tex),FadeOut(name),FadeOut(speed))
            else:
                Animation2=AnimationGroup(FadeOut(tex),FadeOut(name))

        elif (self.iteration_speed>1 or self.fps60!=1) and self.provider==None:
            Animation2=AnimationGroup(FadeOut(tex),FadeOut(speed))
        self.play(Animation,FadeIn(count))
        self.t=0
        value=ValueTracker()
        def up(obj,dt):
            self.t+=1
            if self.t % self.fps60==0:
                flat=[i for l in array for i in l]
                for opacity,square in zip(flat,obj):
                    square.set_opacity(opacity)
                for i in range(self.iteration_speed):
                    change(array)
                    value.increment_value(1)
        if self.iteration_speed>1 or self.fps60!=1:
            self.play(FadeIn(speed))
        squ.add_updater(up)
        count.add_updater(lambda obj:obj.set_value(value.get_value()))
        self.add(count)
        
        self.wait(self.last)
        squ.clear_updaters()
        count.clear_updaters()
        self.play(Animation2,squ.animate.set_opacity(0),squ[25*52].animate.set_opacity(1),FadeOut(count))

class ThreeDwaves(ThreeDScene):
    CONFIG={
        "func":lambda u,d,l,r:u+d+l+r,
        "func_label":r"U+D+L+R",
        "last":8,
        "textype":Tex,
        "iteration_speed":1,
        "fps60":1,
        "provider":None
    }
    def construct(self):
        side=51
        array=[[0 for i in range(side)] for i in range(side)]
        array[25][25]=1
        tex=self.textype(self.func_label).set_width(3).next_to(np.array([-FRAME_X_RADIUS/2-FRAME_Y_RADIUS/2,4,0]),DOWN).fix_in_frame()
        count=Integer().to_corner(DL).fix_in_frame()
        if self.provider != None:
            name=Text(self.provider,font="DengXian").set_width(2).next_to(tex,DOWN).fix_in_frame()

        if self.iteration_speed>1 or self.fps60!=1:
            speed=Tex("\\times",str(self.iteration_speed/self.fps60)).next_to(name,DOWN).fix_in_frame()
        
        
        frame = self.camera.frame
        frame.set_euler_angles(
            theta=-30 * DEGREES,
            phi=70 * DEGREES,
        )

        def map_to(t):
            if t<=0:
                return 0
            elif t>=1:
                return 1
            else:
                return t

        def change(grid):
            width=len(grid[0])
            height=len(grid)
            l=[]
            for i in range(height):
                for j in range(width):
                    l.append([(i,j),map_to(self.func(grid[(i-1)%height][j],grid[(i+1)%height][j],grid[i][(j-1)%width],grid[i][(j+1)%width],))])
            
            for index_and_num in l:
                i,j=index_and_num[0]
                array[i][j]=index_and_num[1]
        
        squ=Square(fill_color=WHITE,stroke_width=0).get_grid(side,side,height=8,buff=0).set_opacity(0.5).move_to(IN*1.5)
        squ[25*51+25].move_to(OUT*1.5)

        self.add(squ)
        Animation=AnimationGroup(FadeIn(tex))
        Animation2=AnimationGroup(FadeOut(tex))
        if self.provider != None :
            Animation=AnimationGroup(FadeIn(tex),FadeIn(name))
            if self.iteration_speed>1 or self.fps60!=1:
                Animation2=AnimationGroup(FadeOut(tex),FadeOut(name),FadeOut(speed))
            else:
                Animation2=AnimationGroup(FadeOut(tex),FadeOut(name))

        elif (self.iteration_speed>1 or self.fps60!=1) and self.provider==None:
            Animation2=AnimationGroup(FadeOut(tex),FadeOut(speed))
        self.play(Animation,FadeIn(count))
        self.t=0
        value=ValueTracker()
        def up(obj,dt):
            self.t+=1
            if self.t % self.fps60==0:
                flat=[i for l in array for i in l]
                for opacity,square in zip(flat,obj):
                    square.move_to((opacity*3-1.5)*OUT+np.array([square.get_x(),square.get_y(),0]))
                for i in range(self.iteration_speed):
                    change(array)
                    value.increment_value(1)
        
        if self.iteration_speed>1 or self.fps60!=1:
            self.play(FadeIn(speed))
        squ.add_updater(up)
        count.add_updater(lambda obj:obj.set_value(value.get_value()).fix_in_frame())
        self.add(count)
        
        self.wait(self.last)
        squ.clear_updaters()
        count.clear_updaters()
        self.play(Animation2,*[square.animate.move_to(IN*1.5+np.array([square.get_x(),square.get_y(),0])) for square in squ],squ[25*52].animate.move_to(OUT*1.5),FadeOut(count))

class test(waves):
    CONFIG={
        "func":lambda u,d,l,r:(u+d+l+r)/4,
        "func_label":r"\frac{U+D+L+R}{4}",
        "provider":"@寂夜霜花",
        "last":4
    }

class test2(waves):
    CONFIG={
        "func":lambda u,d,l,r:((u*u+l*l+r*r+d*d)/4)**0.5,
        "func_label":r"\sqrt{\frac{U^2+D^2+L^2+R^2}{4} }",
        "provider":"@寂夜霜花",
        "last":7,
        "iteration_speed":4
    }

class test3(waves):
    CONFIG={
        "func":lambda u,d,l,r:sum([u,d,l,r])/3.9,
        "func_label":r"\frac{U+D+L+R}{3.9}",
        "provider":"@一碗星空汤",
        "last":8,
    }

class test4(waves):
    CONFIG={
        "func":lambda u,d,l,r:round(np.sin(u+d+l+r)/2+1/2,3),
        "func_label":r"\mathrm{round}\left(\frac{\sin (U+D+L+R)+1}{2},3\right)",
        "provider":"@一碗星空汤",
        "last":20,
        "iteration_speed":4
    }

class test5(waves):
    CONFIG={
        "func":lambda u,d,l,r:(299792458*r)**2-l**2-d**2-u**2,
        "func_label":r"$(cR)^2-U^2-D^2-L^2$\\$c$为光速",
        "textype":TexText,
        "provider":"@NKU的雾里学家",
        "last":8,
        "iteration_speed":1
    }

def func6(u,d,l,r):
    a=(u**0.5+d**0.5+l**0.5+r**0.5)/4
    if a>1-1e-3:
        return 0
    else:
        return a

class test6(waves):
    CONFIG={
        "func":func6,
        "func_label":r"$\frac{\sqrt{U}+\sqrt{D}+\sqrt{L}+\sqrt{R} }{4}$\\结果足够接近$(<0.1\%)~1$时\\输出$0$",
        "provider":"@一碗星空汤",
        "textype":TexText,
        "last":40,
        "fps60":2,
        "iteration_speed":1
    }
t=2
def game(u,d,l,r):
    if u+d+l+r!=4 and u+d+l+r!=0:
        return 1
    else:
        return 0

class test7(waves):
    CONFIG={
        "func":game,
        "func_label":r"$U+D+L+R=0$或$4$输出0,\\其他输出$1$",
        "textype":TexText,
        "provider":"@一碗星空汤",
        "last":20,
        "fps60":2,
        "iteration_speed":1
    }

class test8(waves):
    CONFIG={
        "func":lambda x,y,z,w:(x+.1)*y+x**2*z/2+(x+.3)**3*w/6+x,
        "func_label":r"(U+0.1)D+\frac{U^2L}{2}+\frac{(U+0.3)^3R}{6}+U",
        "provider":"@凡人忆拾",
        "last":12,
        "iteration_speed":1
    }

class test9(waves):
    CONFIG={
        "func":lambda x,y,z,w:np.cos(x+y)+np.sin(z*w),
        "func_label":r"\cos(U+D)+\sin(LR)",
        "provider":"@牛顿了么",
        "last":8,
        "iteration_speed":1
    }

class TwoD_to_ThreeD(ThreeDScene):
    def construct(self):
        side=51
        squ=Square(fill_color=WHITE,stroke_width=0).get_grid(side,side,height=8,buff=0).set_opacity(0)
        squ[25*51+25].set_opacity(1)
        self.add(squ)
        self.wait()
        frame=self.camera.frame
        text=TexText("当然我们也可以用$z$轴来表示透明度").to_edge(DOWN).fix_in_frame()
        self.play(Write(text),frame.animate.set_euler_angles(theta=-30 * DEGREES,phi=70 * DEGREES,),squ.animate.set_opacity(0.5).move_to(IN*1.5),squ[25*52].animate.set_opacity(0.5).move_to(OUT*1.5))
        self.wait()
        self.play(FadeOut(text))
        self.wait()
    
class Dtest1(ThreeDwaves):
    CONFIG={
        "func":lambda x,y,z,w:x/1.9+y/4+z/4,
        "last":8,
        "provider":"@一碗星空汤",
        "func_label":r"\frac{U}{1.9}+\frac{D}{4}+\frac{L}{4}"
    }

class Dtest2(ThreeDwaves):
    CONFIG={
        "func":lambda x,y,z,w:(x+.1)*y+x**2*z/2+(x+.3)**3*w/6+x,
        "func_label":r"(U+0.1)D+\frac{U^2L}{2}+\frac{(U+0.3)^3R}{6}+U",
        "provider":"@凡人忆拾",
        "last":12,
        "iteration_speed":1
    }

class Dtest3(ThreeDwaves):
    CONFIG={
        "func":lambda u,d,l,r:sum([u,d,l,r])/3.9,
        "func_label":r"\frac{U+D+L+R}{3.9}",
        "provider":"@一碗星空汤",
        "last":8,
    }

def P(r,x):
    return (1-r*r)/(1-2*r*np.cos(0.87*PI*x-PI)+r*r)

class Dtest4(ThreeDwaves):
    CONFIG={
        "func":lambda u,d,l,r:P(0.9,np.sum([u,d,l,r])),
        "func_label":r"\frac{19}{181-180\cos (0.87\pi(U+D+L+R)-\pi)}",
        "provider":"@爱哭的Fran",
        "last":40,
        "fps60":2,
    }

class Dtest5(ThreeDwaves):
    CONFIG={
        "func":lambda u,d,l,r:sigmoid((u+d+l+r)/1.5)*2-1,
        "func_label":r"2\mathrm{sigmoid}\left(\frac{U+D+L+R}{1.5}\right)-1",
        "provider":"@一碗星空汤",
        "last":2,
    }

